package com.ray.monitor.manager;

import com.alibaba.fastjson.JSON;
import com.ray.monitor.config.MonitorConfig;
import com.ray.monitor.model.po.ProcessMonitor;
import com.ray.monitor.model.vo.ProcessMonitorVO;
import com.ray.monitor.util.SizeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import oshi.SystemInfo;
import oshi.hardware.GlobalMemory;
import oshi.software.os.OSProcess;
import oshi.software.os.OperatingSystem;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 进程监控信息业务处理
 *
 * @author LiaoYuXing-Ray
 * @version 1.0
 * @createDate 2024/5/23 9:42
 **/
@Slf4j(topic = "Ray.MonitorManager")
@Component
public class MonitorManager {

    @Resource
    MonitorConfig monitorConfig;

    /**
     * 上报监控进程信息
     *
     * @author LiaoYuXing-Ray 2024/5/23 9:43
     **/
    public void reportMonitorInfo() throws Exception {
        // 需要上报的监控信息对象集合
        List<ProcessMonitor> processesList = new ArrayList<>();
        try {
            SystemInfo si = new SystemInfo();
            OperatingSystem os = si.getOperatingSystem();
            GlobalMemory memory = si.getHardware().getMemory();

            // 获取所有运行的经常
            List<OSProcess> processes = os.getProcesses();
            // 系统CPU总数
            int cpuCount = si.getHardware().getProcessor().getLogicalProcessorCount();
            // 系统内存总是
            long totalMem = si.getHardware().getMemory().getTotal();
            // 获取总物理内存大小（以字节为单位）
            long totalPhysicalMemory = memory.getTotal();

            for (OSProcess process : processes) {
                int pid = process.getProcessID();
                // 过滤不需要监控的进程
                if (pid < 1) {
                    continue;
                }

                // 获取 CPU 占用率
                double cpuUsage = process.getProcessCpuLoadBetweenTicks(process);
                // 获取进程的占用内存 RSS（Resident Set Size）以字节为单位
                long rss = process.getResidentSetSize();
                // 计算内存占用百分比
                double memoryUsagePercent = (rss / (double) totalPhysicalMemory) * 100;

                /*
                   上报[CPU]、[内存]超过阈值的可疑进程
                 */
                if (cpuUsage > monitorConfig.getCpuThreshold() || memoryUsagePercent > monitorConfig.getMemoryThreshold()) {
                    ProcessMonitor processMonitor = new ProcessMonitor();
                    processMonitor.setProcessName(process.getName());
                    processMonitor.setPid(pid);
                    processMonitor.setPPid(process.getParentProcessID());
                    processMonitor.setCpu(100d * process.getProcessCpuLoadBetweenTicks(process) / cpuCount);
                    processMonitor.setMemory(100d * process.getResidentSetSize() / totalMem);
                    processMonitor.setRss(process.getResidentSetSize());
                    processMonitor.setThreadCount(process.getThreadCount());
                    processesList.add(processMonitor);
                }
            }

            // 可疑进程
            List<ProcessMonitorVO> processMonitorVOList = new ArrayList<>(processesList.size());

            if (processesList.size() > 0) {
                for (ProcessMonitor processMonitor : processesList) {
                    processMonitorVOList.add(parseProcessMonitorToVO(processMonitor));
                }
            }

            // 打印可疑进程
            log.warn("可疑进程：{}", JSON.toJSON(processMonitorVOList));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private ProcessMonitorVO parseProcessMonitorToVO(ProcessMonitor processMonitor) {
        ProcessMonitorVO parse = new ProcessMonitorVO();
        parse.setProcessName(processMonitor.getProcessName());
        parse.setPid(processMonitor.getPid());
        parse.setPPid(processMonitor.getPPid());
        parse.setCpu(String.format("%.4f", processMonitor.getCpu()) + "%");
        parse.setMemory(String.format("%.4f", processMonitor.getMemory()) + "%");
        parse.setRss(SizeUtils.formatBytes(processMonitor.getRss()));
        parse.setThreadCount(processMonitor.getThreadCount());
        return parse;
    }
}
